package com.econ.powercloud.ems.timing.report;

import com.econ.powercloud.clickhouse.entity.EmsStatisticalDay;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.aop.TimingRetryValid;
import com.econ.powercloud.ems.common.enums.DeviceType;
import com.econ.powercloud.ems.common.enums.ReportIdType;
import com.econ.powercloud.ems.common.util.DateTimeUtil;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.EmsColumnConfig;
import com.econ.powercloud.ems.dal.entity.EmsDevice;
import com.econ.powercloud.ems.pojo.*;
import com.econ.powercloud.ems.service.biz.ClickHouseBizService;
import com.econ.powercloud.ems.service.common.QueryFlashDataCommonService;
import com.econ.powercloud.ems.service.dao.EmsColumnConfigDAO;
import com.econ.powercloud.ems.service.dao.EmsDeviceDAO;
import com.econ.powercloud.ems.util.RedisCacheUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @Author : zjf
 * @Description : BMU统计 定时任务
 * 暂时把以前的逻辑直接移植，有空在进行重写
 * @Date : 2021/9/22 11:32
 * @Modified by : zjf
 */
@Slf4j
@Component
public class BMUDataTask {
    //
    public static final String BMU_TASK = "ems-bmu-task";

    @Autowired
    private RedisCacheUtil redisCacheUtil;
    @Autowired
    private EmsDeviceDAO emsDeviceDAO;
    @Autowired
    private EmsColumnConfigDAO emsColumnConfigDAO;
    @Autowired
    private QueryFlashDataCommonService queryFlashDataCommonService;
    @Autowired
    private ClickHouseBizService clickHouseBizService;

    /**
     * 获取当前累计分钟数
     */
    public int getNowDateToMinute(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        int minute = instance.get(Calendar.MINUTE);
        int hour = instance.get(Calendar.HOUR_OF_DAY) * 60;
        return hour + minute;
    }

    /**
     * 获取当前累计小时数
     */
    public int getNowDateToHour(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return instance.get(Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取当前小时分钟数
     */
    public int getNowHourToMinute(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return instance.get(Calendar.MINUTE);
    }

    /**
     * 每5分钟执行一次
     * BMU报表所需点号每间隔5分钟数据记录
     */
    @Scheduled(cron = "0 */5 * * * ?")
    @TimingRetryValid(lockName = BMU_TASK,timeOutSecond = 60L)
    public void cumulativeTodayChargeData() {
        long currentTime = System.currentTimeMillis();
        Date currentDate = new Date(currentTime);
        //每小时开始执行分钟数范围
        int beginHourForMinute = 3;
        int nowDateToMinute = getNowDateToMinute(currentDate);
        int nowDateToHour = getNowDateToHour(currentDate);
        int nowHourToMinute = getNowHourToMinute(currentDate);
        int beforeDateToHour;
        if (nowDateToHour == 0) {
            beforeDateToHour = 23;
        } else {
            beforeDateToHour = nowDateToHour - 1;
        }
        List<EmsDevice> emsDeviceList = emsDeviceDAO.list();
        Map<String, EmsDevice> emsDeviceMap = emsDeviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, d->d,(p1, p2)->p1));
        //每小时起始插入上一小时数据
        if (beginHourForMinute >= nowHourToMinute) {
            List<EmsStatisticalDay> emsStatisticalDayList = Lists.newArrayList();
            List<RedisHourDataVO> redisHistoryDataList = redisCacheUtil.getBMURedisHistoryDataByHashKey(beforeDateToHour);
            if (!redisHistoryDataList.isEmpty()) {
                for (RedisHourDataVO redisHistoryData : redisHistoryDataList) {
                    String deviceCode = redisHistoryData.getDeviceCode();
                    String columnId = redisHistoryData.getColumnId();
                    String val = redisHistoryData.getVal();
                    Long time = redisHistoryData.getTime();
                    EmsDevice emsDevice = emsDeviceMap.get(deviceCode);
                    String stationId = emsDevice.getEnergyStationId();
                    String equipmentId = emsDevice.getEnergyEquipmentId();
                    EmsStatisticalDay emsStatisticalDay = EmsStatisticalDay.builder().energyStationId(stationId).energyEquipmentId(equipmentId)
                            .reportId(ReportIdType.BMU.getCode()).deviceCode(deviceCode).columnId(columnId).val(val).
                                    time(time).gmtCreate(currentDate).build();
                    emsStatisticalDayList.add(emsStatisticalDay);
                }
//                emsStatisticalDayDAO.insertBatch(emsStatisticalDayList);
                clickHouseBizService.bmuStatisticalDayListDataIntoClickHouse(emsStatisticalDayList);
                if (beforeDateToHour == 23) {
                    redisCacheUtil.delByKey(SysConstant.BMS_HIS_HOUR + SysConstant.asterisk);
                }
            }
        }
        //储能站、储能装置 对应列配置信息
        Map<String, Map<String, List<EmsColumnConfig>>> emsColumnConfigForEquipment = Maps.newHashMap();
        List<EmsDevice> bmuDeviceList = Lists.newArrayList();
        List<EmsColumnConfig> emsColumnConfigs = emsColumnConfigDAO.selectAll();
        Map<String, List<EmsColumnConfig>> deviceCodeToEmsColumnConfig = Maps.newHashMap();
        if(CollectionUtils.isNotEmpty(emsColumnConfigs)){
            deviceCodeToEmsColumnConfig = emsColumnConfigs.stream().collect(Collectors.groupingBy(d->d.getReportId()));
        }
        List<EmsColumnConfig> emsColumnConfigList = deviceCodeToEmsColumnConfig.get(ReportIdType.BMU.getCode());
        if (CollectionUtils.isNotEmpty(emsColumnConfigList)) {
            Map<String, List<EmsColumnConfig>> stationMap = emsColumnConfigList.stream().collect(Collectors.groupingBy(d -> d.getEnergyStationId()));
            stationMap.forEach((k, v) -> {
                Map<String, List<EmsColumnConfig>> equipmentMap = v.stream().collect(Collectors.groupingBy(d -> d.getEnergyEquipmentId()));
                Map<String, List<EmsColumnConfig>> result = Maps.newHashMap();
                equipmentMap.forEach((k1, v1) -> {
                    result.put(k1, v1);
                });
                emsColumnConfigForEquipment.put(k, result);
            });
        }
        //获取所有的BMU设备
        List<EmsDevice> clusterList = emsDeviceList.stream().filter(d-> DeviceType.CLUSTER.getCode().equals(d.getDeviceType())).collect(Collectors.toList());
        bmuDeviceList.addAll(clusterList);
        //获取所有实时数据点号后缀
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        for (EmsDevice emsDevice : bmuDeviceList) {
            List<EmsColumnConfig> columnIdList = Lists.newArrayList();
            if(MapUtils.isEmpty(emsColumnConfigForEquipment.get(emsDevice.getEnergyStationId())) ||
                    CollectionUtils.isEmpty(emsColumnConfigForEquipment.get(emsDevice.getEnergyStationId()).get(emsDevice.getEnergyEquipmentId()))){
                continue;
            }
            columnIdList.addAll(emsColumnConfigForEquipment.get(emsDevice.getEnergyStationId()).get(emsDevice.getEnergyEquipmentId()));
            for (EmsColumnConfig columnId : columnIdList) {
                locationVOList.add(EmsDeviceLocationVO.builder()
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + emsDevice.getModuleCode() + SysConstant.SPOT + columnId.getColumnId())
                        .deviceCode(emsDevice.getDeviceCode()).initDeviceCode(emsDevice.getInitDeviceCode())
                        .dit(emsDevice.getModuleCode() + SysConstant.SPOT + columnId.getColumnId())
                        .build());
            }
        }
        List<FlashDataVO> redisFlashDataList = queryFlashDataCommonService.getFlashData(JacksonUtil.convertToList(locationVOList, QueryDataVO.class));
        computeProcess(nowDateToHour, bmuDeviceList, redisFlashDataList, emsColumnConfigForEquipment, nowDateToMinute);
    }

    /**
     * 没五分钟统计每个点号每小时min、max
     */
    public void computeProcess(Integer nowDateToHour, List<EmsDevice> bmuDeviceList, List<FlashDataVO> redisFlashDataList, Map<String, Map<String, List<EmsColumnConfig>>> emsColumnConfigForEquipment, Integer nowDateToMinute) {
        long currentTime = System.currentTimeMillis();
        Date currentDate = new Date(currentTime);
        Long lastHourTime = DateTimeUtil.getStartOfHour(currentDate);
        Map<String, List<Map<String, String>>> computeLogicForBmu = Maps.newHashMap();
        Map<String, FlashDataVO> redisFlashDataForPid = redisFlashDataList.stream().collect(Collectors.toMap(FlashDataVO::getPid, Function.identity()));
        //封装各个BMU中Redis已计算的数据的查询条件（deviceCode，columnId 值）
        Map<String, EmsDevice> bmuDeviceMap = bmuDeviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, d->d,(p1, p2)->p1));
        for (EmsDevice emsDevice : bmuDeviceList) {
            List<Map<String, String>> computeLogicForBmuList = Lists.newArrayList();
            String energyStationId = emsDevice.getEnergyStationId();
            String energyEquipmentId = emsDevice.getEnergyEquipmentId();
            String deviceId = emsDevice.getDeviceCode();
            List<EmsColumnConfig> emsColumnConfigList = Lists.newArrayList();
            if(MapUtils.isNotEmpty(emsColumnConfigForEquipment.get(energyStationId)) &&
                CollectionUtils.isNotEmpty(emsColumnConfigForEquipment.get(energyStationId).get(energyEquipmentId))){
                emsColumnConfigList.addAll(emsColumnConfigForEquipment.get(energyStationId).get(energyEquipmentId));
            }
            if(CollectionUtils.isEmpty(emsColumnConfigList)){
                continue;
            }
            for (EmsColumnConfig emsColumnConfig : emsColumnConfigList) {
                Map<String, String> computeLogicMap = Maps.newHashMap();
                String columnId = emsColumnConfig.getColumnId();
                String pid = emsDevice.getInitDeviceCode() + SysConstant.SPOT + emsDevice.getModuleCode() + SysConstant.SPOT + columnId;
                //log.info("pid: ", pid);
                FlashDataVO redisFlashData = redisFlashDataForPid.get(pid);
                String value;
                if(null == redisFlashData){
                    value = SysConstant.CABLE;
                }else {
                    value = redisFlashData.getVal();
                }
                //log.info("value: " + value);
                computeLogicMap.put(columnId,value);
                computeLogicForBmuList.add(computeLogicMap);
            }
            computeLogicForBmu.put(deviceId, computeLogicForBmuList);
        }
        //上一次查询结果值
        List<RedisHourDataVO> redisHourDataListForUpdate = Lists.newArrayList();
        List<RedisHourDataVO> redisHistoryDataList = redisCacheUtil.getBMURedisHistoryDataByHashKey(nowDateToHour);
        Map<String, Map<String, RedisHourDataVO>> redisHistoryDataForColumnIdAndBmu = Maps.newHashMap();
        Map<String, List<RedisHourDataVO>> redisHistoryDataListForDeviceCode = redisHistoryDataList.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode()));
        redisHistoryDataListForDeviceCode.forEach((k, v) -> {
            Map<String, RedisHourDataVO> RedisHistoryDataForColumnId = v.stream().collect(Collectors.toMap(RedisHourDataVO::getColumnId, Function.identity()));
            redisHistoryDataForColumnIdAndBmu.put(k, RedisHistoryDataForColumnId);
        });
        computeLogicForBmu.forEach((bmuDeviceCode, computeLogicMapList) -> {
            EmsDevice bmuDevice = bmuDeviceMap.get(bmuDeviceCode);
            for (Map<String, String> computeLogicMap : computeLogicMapList) {
                computeLogicMap.forEach((columnId, cPidForValue) -> {
                    RedisHourDataVO redisHourDataVO = null;
                    if (null != redisHistoryDataForColumnIdAndBmu.get(bmuDeviceCode)) {
                        redisHourDataVO = redisHistoryDataForColumnIdAndBmu.get(bmuDeviceCode).get(columnId);
                    }
                    if(null != redisHourDataVO ){
                        String val = redisHourDataVO.getVal();
                        if(!cPidForValue.equals(val)){
                            redisHourDataVO = RedisHourDataVO.builder().pid(bmuDevice.getInitDeviceCode() + SysConstant.SPOT + bmuDevice.getModuleCode() + SysConstant.SPOT + columnId)
                                    .deviceCode(bmuDeviceCode).columnId(columnId)
                                    .val(cPidForValue).minute(nowDateToMinute).time(lastHourTime).gmtCreate(System.currentTimeMillis()).build();
                            redisHourDataListForUpdate.add(redisHourDataVO);
                        }
                    }else {
                        redisHourDataVO = RedisHourDataVO.builder().pid(bmuDevice.getInitDeviceCode() + SysConstant.SPOT + bmuDevice.getModuleCode() + SysConstant.SPOT + columnId)
                                .deviceCode(bmuDeviceCode).columnId(columnId)
                                .val(cPidForValue).minute(nowDateToMinute).time(lastHourTime).gmtCreate(System.currentTimeMillis()).build();
                        redisHourDataListForUpdate.add(redisHourDataVO);
                    }
                });
            }
        });
        if (redisHourDataListForUpdate != null && !redisHourDataListForUpdate.isEmpty()) {
            redisCacheUtil.addBMURedisHistoryDataByHashkey(nowDateToHour, redisHourDataListForUpdate);
        }
    }

}
